package git.soulbgm.security.controller;

import git.soulbgm.common.constant.HttpStatus;
import git.soulbgm.common.pojo.ResultData;
import git.soulbgm.common.pojo.ReturnCode;
import git.soulbgm.pojo.vo.OnlineUserInfo;
import git.soulbgm.security.config.AuthorityConfig;
import git.soulbgm.security.constant.SecurityConstants;
import git.soulbgm.security.pojo.LoginUser;
import git.soulbgm.security.service.OnlineUserService;
import git.soulbgm.security.service.TokenService;
import git.soulbgm.utils.RequestUtil;
import git.soulbgm.utils.ResponseUtil;
import git.soulbgm.utils.SpringBeanUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * 用于跳转接口
 *
 * @author SoulBGM
 * @date 2020-08-04
 */
@Slf4j
@RestController
public class SecurityController {

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Autowired
    private AuthorityConfig config;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private TokenService tokenService;

    @PostMapping("login")
    public ResultData login(String username, String password) {
        try {
            Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
            LoginUser loginUser = (LoginUser) authentication.getPrincipal();
            boolean flag = tokenService.checkIfCanLogin(loginUser.getUsername());
            if (!flag) {
                return ResultData.getResultData(ReturnCode.LOGIN_FAIL.code, "账号已在另一地址登录");
            }
            log.info("{},登录成功,登录IP: {}", loginUser.getNickname(), loginUser.getLoginIpAddress());
            String token = tokenService.createToken(loginUser);
            return ResultData.getResultData(ReturnCode.SUCCESS, token);
        } catch (AuthenticationException e) {
            if (e instanceof BadCredentialsException) {
                return ResultData.getResultData(ReturnCode.USERNAME_OR_PASSWORD_IS_INCORRECT);
            } else {
                return ResultData.getResultData(ReturnCode.LOGIN_FAIL.code, e.getMessage());
            }
        }
    }

    @GetMapping("getInitPassword")
    public ResultData getInitPassword() {
        return ResultData.getResultData(ReturnCode.SUCCESS, config.getInitPassword());
    }

    @GetMapping("loginStatus")
    public ResultData loginStatus() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null && authentication.getPrincipal() instanceof LoginUser) {
            LoginUser userDetails = (LoginUser) authentication.getPrincipal();
            return ResultData.getResultData(ReturnCode.HAS_LOGGED, userDetails);
        } else {
            return ResultData.getResultData(ReturnCode.NOT_LOGIN);
        }
    }

    @PostMapping("checkPassword")
    public ResultData checkPassword(String password) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null && authentication.getPrincipal() instanceof LoginUser) {
            LoginUser userDetails = (LoginUser) authentication.getPrincipal();
            if (bCryptPasswordEncoder.matches(password, userDetails.getPassword())) {
                return ResultData.getResultData(ReturnCode.SUCCESS);
            }
        }
        return ResultData.getResultData(401, "密码错误");
    }

    @GetMapping("sessionExpired")
    public void sessionExpired(HttpServletResponse response) {
        int code = HttpStatus.UNAUTHORIZED;
        String msg = "会话过期,请重新登录";
        ResponseUtil.renderError(response, code, msg);
    }

    @GetMapping("sessionInvalidation")
    public void sessionInvalidation(HttpServletResponse response) {
        int code = HttpStatus.UNAUTHORIZED;
        String msg = "会话无效,请重新登录";
        ResponseUtil.renderError(response, code, msg);
    }

    @GetMapping("loginSuccess")
    public ResultData loginSuccess(HttpServletRequest request) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        LoginUser userDetails = (LoginUser) authentication.getPrincipal();
        String ip = RequestUtil.getRemoteIpByServletRequest(request, true);
        log.info("{},登录成功,登录IP: {}", userDetails.getNickname(), ip);
        return ResultData.getResultData(ReturnCode.LOGIN_SUCCESS, userDetails);
    }

    @GetMapping("loginFailure")
    public ResultData loginFailure(HttpServletRequest request) {
        String ip = RequestUtil.getRemoteIpByServletRequest(request, true);
        log.info("登录失败,登录IP: {}", ip);
        String msg = "登录失败";
        return ResultData.getResultData(HttpStatus.UNAUTHORIZED, msg);
    }

    @GetMapping("accessDenied")
    public void accessDenied(HttpServletRequest request, HttpServletResponse response) {
        if (!response.isCommitted()) {
            ResponseUtil.renderError(response, HttpStatus.FORBIDDEN, "访问被拒绝，权限不足");
        }
    }

    @Value("${authority.loginMode}")
    private int loginMode;

    private OnlineUserService getOnlineUserService() {
        OnlineUserService service;
        if (loginMode == SecurityConstants.LOGIN_MODE_COOKIE) {
            service = (OnlineUserService) SpringBeanUtil.getBean("sessionOnlineUserService");
        } else {
            service = (OnlineUserService) SpringBeanUtil.getBean("tokenOnlineUserService");
        }
        return service;
    }

    @GetMapping("getOnlineUser")
    public ResultData getOnlineUser(String username, String ip) {
        OnlineUserService service = getOnlineUserService();
        List<OnlineUserInfo> list = service.getOnlineUser(username, ip);
        return ResultData.getResultData(ReturnCode.SUCCESS, list);
    }

    @PostMapping("forcedOfflineUser")
    public ResultData forcedOfflineUser(@RequestBody List<String> sessionList) {
        OnlineUserService service = getOnlineUserService();
        boolean flag = service.forcedOfflineUser(sessionList);
        if (flag) {
            return ResultData.getResultData(ReturnCode.SUCCESS);
        } else {
            return ResultData.getResultData(ReturnCode.LOGOUT_FAIL);
        }
    }

}
